#include <iostream>
#include "math.h"

#include "Complex.h"
#include <complex>

using namespace std;

Complex::Complex()
    :m_real(0), m_imag(0)
{}

Complex::Complex(cType _real)
    :m_real(_real), m_imag(0)
    {}

Complex::Complex(const cType& _real, const cType& _img)
            :m_real(_real), m_imag(_img)
{}



Complex& Complex::operator=(const Complex& _rhs)
{
    if (this == &_rhs) {return *this;} // handle self assignment
    m_real = _rhs.m_real;
    m_imag = _rhs.m_imag;

    return *this;
}

Complex& Complex::operator=(cType _real)
{
    m_real = _real;
    m_imag = 0;

    return *this;
}


ostream& operator<<(ostream& _os, const Complex& _cmp)
{
    return _os<<"("<<_cmp.m_real<<", "<<_cmp.m_imag<<"i)";
}


istream& operator>>(istream& _is, Complex& _cmp)
{
    return _is>>_cmp.m_real>>_cmp.m_imag;
}


Complex& Complex::operator+=(const Complex& _cmp)
{
    m_real += _cmp.m_real;
    m_imag += _cmp.m_imag;

    return *this;
}


Complex& Complex::operator-=(const Complex& _cmp)
{
    m_real -= _cmp.m_real;
    m_imag -= _cmp.m_imag;

    return *this;
}

Complex& Complex::operator*=(const Complex& _cmp)
{           //   a1*a2 - b1*b2 + i(a1*b2 + a2*b1)
    Complex tmp(m_real, m_imag);
    tmp.m_real = _cmp.m_real * m_real - _cmp.m_imag * m_imag;
    tmp.m_imag = _cmp.m_real * m_imag + _cmp.m_imag * m_real;
    m_real = tmp.m_real;
    m_imag = tmp.m_imag;

    return *this;
}


Complex& Complex::operator/=(const Complex& _cmp)
{
    Complex tmp(m_real, m_imag);
    tmp = (*this)*_cmp.Conj();
    m_real =  tmp.m_real / _cmp.Norm();
    m_imag =  tmp.m_imag / _cmp.Norm();

     return *this;
}


Complex operator+(const Complex& _cmp1, const Complex& _cmp2)
{
    Complex tmp(_cmp1);
    return tmp+=_cmp2;
}

Complex operator-(const Complex& _cmp1, const Complex& _cmp2)
{
    Complex tmp(_cmp1);
    return tmp-=_cmp2;
}

Complex operator*(const Complex& _cmp1, const Complex& _cmp2)
{
    Complex tmp(_cmp1);
    return tmp*=_cmp2;
}

Complex operator/(const Complex& _cmp1, const Complex& _cmp2)
{
    Complex tmp(_cmp1);
    return tmp/=_cmp2;
}

void Complex::SetReal(const cType& _real)
{
    m_real = _real;
}

void Complex::SetImg(const cType& _img)
{
    m_imag = _img;
}

cType Complex::GetReal() const
{
    return m_real;
}

cType Complex::GetImg() const
{
    return m_imag;
}

cType Complex::Abs() const
{
    return sqrt(Norm());
}

Complex Complex::Conj() const
{
    Complex c(m_real, -m_imag);
    return c;
}

cType Complex::Norm() const
{
    return (m_real*m_real + m_imag*m_imag);
}

bool Complex::operator==(const Complex& _cmp)
{
    return (m_real == _cmp.m_real) && (m_imag == _cmp.m_imag);
}

bool Complex::operator!=(const Complex& _cmp)
{
    return !operator==(_cmp);
}



//------------------------------------------------------------------------------------------------------------------------------------------------

int main()
{
    Complex c1(20, -8);
    Complex c2(-3.6, 4);
    Complex c3(-3.6,4);

    //c3 = 3;
    cout<<c3<<endl;

//    cout<<"Enter first complex number"<<endl;
//    cin>>c1;
//    cout<<"Enter second complex number"<<endl;
//    cin>>c2;

    cout<<c1 * c2<<endl;
    cout<<c1.Conj()<<endl;
    cout<<c2.Abs()<<endl;
    cout<<c1/c2<<endl;

    cout<<(c2 == c3)<<endl;
    cout<<(1+c2)<<endl;

    return 0;
}
